using System;
using System.Collections.Generic;
using System.Text;
using VSSDKAssist.Assets.Actions.Base;
using VSSDKAssist.Enums;
using Microsoft.Practices.RecipeFramework;
using Microsoft.Practices.RecipeFramework.VisualStudio.Library.Templates;
using VSSDKAssist.Assets.Actions.VisualStudio;
using System.Diagnostics;
using EnvDTE;
using VSSDKAssist.Assets.Actions.VisualStudio.VisualStudio;
using VSSDKAssist.Assets.Helpers;
using VSSDKAssist.Recipes.Common.Actions;
using System.Collections.Specialized;
using System.ComponentModel;

namespace VSSDKAssist.Recipes.SubscribeToEvents
{
	/// <summary>
	/// Action that creates a VS Event subscription
	/// </summary>
	public class SubscribeToEventsAction : ActionBase
	{
		#region Properties
		private Project project;

		/// <summary>
		/// Gets or sets the project.
		/// </summary>
		/// <value>The project.</value>
		[Input(Required = true)]
		public Project Project
		{
			get { return project; }
			set { project = value; }
		}

		private CodeClass codeClass;

		/// <summary>
		/// Gets or sets the code class.
		/// </summary>
		/// <value>The code class.</value>
		[Input(Required = true)]
		public CodeClass CodeClass
		{
			get { return codeClass; }
			set { codeClass = value; }
		}

		private VSEvent vsEvent;

		/// <summary>
		/// Gets or sets the VS event.
		/// </summary>
		/// <value>The VS event.</value>
		[Input(Required = true)]
		public VSEvent VSEvent
		{
			get { return vsEvent; }
			set { vsEvent = value; }
		}

		private string commandId;

		/// <summary>
		/// Gets or sets the command id.
		/// </summary>
		/// <value>The command id.</value>
		[Input(Required = false)]
		public string CommandId
		{
			get { return commandId; }
			set { commandId = value; }
		}

		private string commandGuid;

		/// <summary>
		/// Gets or sets the command GUID.
		/// </summary>
		/// <value>The command GUID.</value>
		[Input(Required = false)]
		public string CommandGuid
		{
			get { return commandGuid; }
			set { commandGuid = value; }
		}
		#endregion

		/// <summary>
		/// Called when [execute].
		/// </summary>
		protected override void OnExecute()
		{
			bool addRefenceToDTE = false;

			string textTemplate = @"TT\SubscribeToEvents\";
			string initializeContent = string.Empty;
			string disposeContent = string.Empty;

			switch(this.vsEvent)
			{
				case VSEvent.BuildEvents:
					textTemplate += "BuildEvents.tt";
					initializeContent = "AdviseBuildEvents();";
					disposeContent = "UnAdviseBuildEvents();";
					addRefenceToDTE = true;
					break;
				case VSEvent.CommandEvents:
					textTemplate += "CommandEvents.tt";
					initializeContent = "AdviseCommandEvents();";
					disposeContent = "UnAdviseCommandEvents();";
					addRefenceToDTE = true;
					break;
				case VSEvent.ProjectItemEvents:
					textTemplate += "ProjectItemEvents.tt";
					initializeContent = "AdviseProjectItemEvents();";
					disposeContent = "UnAdviseProjectItemEvents();";
					addRefenceToDTE = true;
					break;
				case VSEvent.SolutionEvents:
					textTemplate += "SolutionEvents.tt";
					initializeContent = "AdviseSolutionEvents();";
					disposeContent = "UnAdviseSolutionEvents();";
					this.codeClass.AddImplementedInterface(
						"Microsoft.VisualStudio.Shell.Interop.IVsSolutionEvents3", -1);
					break;
				case VSEvent.RunningDocTableEvents:
					textTemplate += "RDTEvents.tt";
					initializeContent = "AdviseRDTEvents();";
					disposeContent = "UnAdviseRDTEvents();";
					this.codeClass.AddImplementedInterface(
						"Microsoft.VisualStudio.Shell.Interop.IVsRunningDocTableEvents3", -1);
					break;
				case VSEvent.FileChangeEvents:
					textTemplate += "FileChangeEvents.tt";
					initializeContent = "AdviseFileChangeEvents();";
					disposeContent = "UnAdviseFileChangeEvents();";
					this.codeClass.AddImplementedInterface(
						"Microsoft.VisualStudio.Shell.Interop.IVsFileChangeEvents", -1);
					break;
				default:
					return;
			}

			//Add/Update Initialize method
			using(AddVSPackageInitializeFunctionAction addVSPackageInitializeFunctionAction = new AddVSPackageInitializeFunctionAction())
			{
				addVSPackageInitializeFunctionAction.Site = this.Site;
				addVSPackageInitializeFunctionAction.CodeClass = this.CodeClass;
				addVSPackageInitializeFunctionAction.Execute();

				FileCodeModelHelper.InsertTextToCodeElement(
					addVSPackageInitializeFunctionAction.CodeFunction as CodeElement, initializeContent);
			}

			//Add/Update Dispose method
			using(AddVSPackageDisposeFunctionAction addVSPackageDisposeFunctionAction = new AddVSPackageDisposeFunctionAction())
			{
				addVSPackageDisposeFunctionAction.Site = this.Site;
				addVSPackageDisposeFunctionAction.CodeClass = this.CodeClass;
				addVSPackageDisposeFunctionAction.Execute();

				FileCodeModelHelper.InsertTextToCodeElement(
					addVSPackageDisposeFunctionAction.CodeFunction as CodeElement, disposeContent);
			}

			//Add subscription implementation
			using(TextTemplateAction textTemplateAction = new TextTemplateAction())
			{
				if(this.VSEvent == VSEvent.CommandEvents)
				{
					TypeDescriptor.GetProperties(textTemplateAction)["CommandId"].SetValue(textTemplateAction, this.CommandId);
					TypeDescriptor.GetProperties(textTemplateAction)["CommandGuid"].SetValue(textTemplateAction, this.CommandGuid);
				}

				textTemplateAction.Site = this.Site;
				textTemplateAction.Template = textTemplate;
				textTemplateAction.Execute();

				FileCodeModelHelper.InsertTextToCodeElement(
					this.CodeClass as CodeElement, textTemplateAction.Content);
			}

			if(addRefenceToDTE)
			{
				//Add assembly references
				using(AddProjectReferenceAction addProjectReferenceAction = new AddProjectReferenceAction())
				{
					addProjectReferenceAction.Site = this.Site;
					addProjectReferenceAction.ReferencedAssembly = "EnvDTE.dll";
					addProjectReferenceAction.ReferringProject = this.Project;

					addProjectReferenceAction.Execute();
				}
			}
		}
	}
}